package com.nettyPractice;


import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.AllArgsConstructor;

import java.util.List;

@AllArgsConstructor
public class NettyKryoDecoder extends ByteToMessageDecoder {
    private final Serializer serializer;
    private final Class<?> genericClass;

    /**
     * Netty传输的消息长度也就是对象序列化后对应的字节数组的大小，存储在 ByteBuf 头部
     */
    private static final int BODY_LENGTH = 4;


    /**
     * 解码 ByteBuf 对象
     *
     * @param channelHandlerContext 解码器关联的 ChannelHandlerContext 对象
     * @param byteBuf  "入站"数据，也就是 ByteBuf 对象
     * @param list 解码之后的数据对象需要添加到 out 对象里面
     */
    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
        //  //1.byteBuf中写入的消息长度所占的字节数已经是4了，所以 byteBuf 的可读字节必须大于 4，
        if(byteBuf.readableBytes() >= BODY_LENGTH){
            //2.标记当前readIndex的位置，以便后面重置readIndex 的时候使用
            byteBuf.markReaderIndex();
            //3.读取消息的长度
            //注意：byteBuf.readInt()方法会让他的readIndex增加4
            int dataLength = byteBuf.readInt();
            // 4.遇到不合理的数据包，跳过
            if(dataLength < 0 || byteBuf.readableBytes() < 0){
//                log.error("数据长度小于0，或者可读字节小于0，数据长度：{}",dataLength);
               return;
            }
            // 5.如果可读字节数小于我们读取的长度字段，说明是不完整的消息包，重置readIndex
            if(byteBuf.readableBytes() < dataLength){
                byteBuf.resetReaderIndex();
                return;
            }
            //6. 进行序列化操作
            byte[] body = new byte[dataLength];
            byteBuf.readBytes(body);
            //7.将字节数组反序列化成对象
            Object obj = serializer.deserialize(body,genericClass);
            list.add(obj);
//            log.info("成功解码对象：{}",obj);
        }
    }
}
